package com.ppgames.gm.gmsystem;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * GM 系统的核心类
 * 包含：Constant Util
 *
 * @author Joeg
 * @email 840459673@qq.com
 * @date 2018/4/19
 */
@Component
public class GmCore {

    private static final Logger logger = LoggerFactory.getLogger(GmCore.class);


    public static ConcurrentHashMap<String, String> TOKEN_CACHE = new ConcurrentHashMap<>();


    @Autowired
    private ApplicationContext _applicationContext;

    @PostConstruct
    public void init() {
        GmCore.applicationContext = _applicationContext;
    }

    public static ApplicationContext applicationContext;


    /**
     * 获取请求上下文信息
     *
     * @return 请求上下文信息
     */
    public static GmContext context() {
        return GmContext.getContext();
    }

    public static class Constant {
        // 前端传入的token标识
        public static final String TOKEN_VIEW_FLAG = "__gm_token__";
        public static final String TOKEN_PREFIX = "token:";
        public static final String TOKEN_VALUE = "*";

        // token存储key
        public static final String TOKEN_INFO_FLAG = "auth:token:info:";
        // Token Id 关联 key : dew:auth:token:id:rel:<code> value : <token Id>
        public static final String TOKEN_ID_REL_FLAG = "auth:token:id:rel:";


    }


    /**
     * 常用工具
     */
    public static class Util {

        public static String getToken(String token) {
            return new StringBuilder().append(Constant.TOKEN_PREFIX).append(":").append(token).toString();
        }

        private static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
                "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
                "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
                "W", "X", "Y", "Z"};

        public static String createUUID() {
            return UUID.randomUUID().toString().replace("-", "");
        }

        public static String createShortUUID() {
            StringBuilder shortBuffer = new StringBuilder();
            String uuid = createUUID();
            for (int i = 0; i < 8; i++) {
                String str = uuid.substring(i * 4, i * 4 + 4);
                int x = Integer.parseInt(str, 16);
                shortBuffer.append(chars[x % 0x3E]);
            }
            return shortBuffer.toString();
        }

        public static String getRealIP(HttpServletRequest request) {
            Map<String, String> requestHeader = new HashMap<>();
            Enumeration<String> header = request.getHeaderNames();
            while (header.hasMoreElements()) {
                String key = header.nextElement();
                requestHeader.put(key.toLowerCase(), request.getHeader(key));
            }
            return getRealIP(requestHeader, request.getRemoteAddr());
        }

        public static String getRealIP(Map<String, String> requestHeader, String remoteAddr) {
            if (requestHeader.containsKey("x-forwarded-for") && requestHeader.get("x-forwarded-for") != null && !requestHeader.get("x-forwarded-for").isEmpty()) {
                return requestHeader.get("x-forwarded-for");
            }
            if (requestHeader.containsKey("wl-proxy-client-ip") && requestHeader.get("wl-proxy-client-ip") != null && !requestHeader.get("wl-proxy-client-ip").isEmpty()) {
                return requestHeader.get("wl-proxy-client-ip");
            }
            if (requestHeader.containsKey("x-forwarded-host") && requestHeader.get("x-forwarded-host") != null && !requestHeader.get("x-forwarded-host").isEmpty()) {
                return requestHeader.get("x-forwarded-host");
            }
            return remoteAddr;
        }

        private static ExecutorService executorService = Executors.newCachedThreadPool();

        public static void newThread(Runnable fun) {
            executorService.execute(fun);
        }


    }

    public static class BeanUtil {

        // Spring Bean 工厂
        public static DefaultListableBeanFactory beanFactory;

        //注意在spring初始化刷新后要调用这个init方法来获得新的beanFactory对象
        public static void init(ApplicationContext applicationContext) {

            ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) GmCore.applicationContext;
            beanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory();
        }


        public static boolean registerBean(String className, String beanKey, Map<String, Object> propertyMap,
                                           Map<String, String> referenceMap, List<Object> propertyConstrList,
                                           List<String> referenceConstrList, String destroyMethod) {


            // 判断Spring容器中是否存在该Bean
            if (beanFactory.containsBeanDefinition(className)) {
                return true;
            }


            BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(className);
            bdb.getBeanDefinition().setAttribute("id", beanKey);

            // 设置bean参数属性
            if (propertyMap != null && !propertyMap.isEmpty()) {
                Iterator<String> propertyKeys = propertyMap.keySet().iterator();
                while (propertyKeys.hasNext()) {
                    String keyString = propertyKeys.next();
                    bdb.addPropertyValue(keyString, propertyMap.get(keyString));
                }
            }


            // 设置bean参数引用
            if (referenceMap != null && !referenceMap.isEmpty()) {
                Iterator<String> referenceKeys = referenceMap.keySet().iterator();
                while (referenceKeys.hasNext()) {
                    String keyString = referenceKeys.next();
                    bdb.addPropertyReference(keyString, referenceMap.get(keyString));
                }
            }
            // 设置bean构造参数属性
            if (propertyConstrList != null && !propertyConstrList.isEmpty()) {
                for (int i = 0; i < propertyConstrList.size(); i++) {
                    bdb.addConstructorArgValue(propertyConstrList.get(i));
                }
            }
            // 设置bean构造参数引用
            if (referenceConstrList != null && !referenceConstrList.isEmpty()) {
                for (int i = 0; i < referenceConstrList.size(); i++) {
                    bdb.addConstructorArgReference(referenceConstrList.get(i));
                }
            }

            if (destroyMethod != null && !destroyMethod.isEmpty()) {
                bdb.setDestroyMethodName(destroyMethod);
            }

            beanFactory.registerBeanDefinition(beanKey, bdb.getBeanDefinition());

            return true;

/*


            // 通过BeanDefinitionBuilder创建bean定义
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            // 设置属性userService,此属性引用已经定义的bean:userService,这里userService已经被spring容器管理了.
            beanDefinitionBuilder.addPropertyReference("userService", "userService");
            beanDefinitionBuilder.addConstructorArgValue()
            beanDefinitionBuilder.
*/

        }

        /**
         * 获取Bean
         *
         * @param requiredType
         * @return
         */
        public static <T> T getBean(Class<T> requiredType) {
            return beanFactory.getBean(requiredType);
        }

        /**
         * 获取bean
         *
         * @param beanName
         * @param requiredType
         * @return
         */
        public static <T> T getBean(String beanName, Class<T> requiredType) {
            return beanFactory.getBean(beanName, requiredType);
        }

    }




}
